package com.ruoyi.service;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import com.nxhz.redis.redisson.api.guid.GuidSnowRedisUtil;
import com.nxhz.redis.redisson.api.guid.SnowflakeIdFactory;
import lombok.extern.slf4j.Slf4j;

import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.LongAdder;

@Service
@Slf4j
public class GuidRedisService implements ApplicationListener<WebServerInitializedEvent> {
	private static final Logger LOGGER = LoggerFactory.getLogger(GuidRedisService.class);

	private static final String GUID_WORK_LIST="GUID_WORK_LIST";
	private static final String GUID_WORK_SET="GUID_WORK_SET";

	private int serverPort;

	Set<Long> set = new CopyOnWriteArraySet<>();

	@Override
	public void onApplicationEvent(WebServerInitializedEvent event) {
		this.serverPort = event.getWebServer().getPort();
	}

	public String getPort(){
		InetAddress  address = null;
		try {
			address = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return address.getHostAddress()+":"+this.serverPort;


	}


	@Resource
	private RedisTemplate<String,Object> redisTemplate = null;

	@Resource
	private RedissonClient redissonClient;

	public GuidRedisService() {
	}

	public long nextId() {

		GuidSnowRedisUtil.initGuidSnowRedisUtil(redissonClient,redisTemplate,getPort());
		SnowflakeIdFactory snowflakeIdFactory = SnowflakeIdFactory.getInstance();
		LOGGER.debug("RedisGuidService.nextId() snowFlakeWorker={}", snowflakeIdFactory);
		long guid = snowflakeIdFactory.nextId();
		return guid;
	}


	public Set<Long> create() {
		GuidSnowRedisUtil.initGuidSnowRedisUtil(redissonClient,redisTemplate,getPort());
		SnowflakeIdFactory snowflakeIdFactory = SnowflakeIdFactory.getInstance();
		redisTemplate.delete(GUID_WORK_SET);
		redisTemplate.delete(GUID_WORK_LIST);

		final CountDownLatch countDownLatch = new CountDownLatch(1);

		ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("redis-work-id-%d").build();
		ExecutorService executor = Executors.newFixedThreadPool(500,namedThreadFactory);
		LongAdder longAdder=new LongAdder();
		int idx=0;
		try {
			for (idx = 0; idx < 3000000; idx++) {
				LOGGER.debug("Thread={}, idx={}", Thread.currentThread().getName(), idx);
				executor.submit(() -> {
					try {
						countDownLatch.await();
						long guid = snowflakeIdFactory.nextId();
						LOGGER.debug("Thread={}, guid={}", Thread.currentThread().getName(), guid);
						redisTemplate.boundSetOps(GUID_WORK_SET).add(guid);
						redisTemplate.boundListOps(GUID_WORK_LIST).leftPush(guid);
					} catch (Throwable th) {
						LOGGER.error("RedisGuidService.create() throwable", th);
					}
				});
			}
			LOGGER.error("idx生成池大小:{}=====executor.queueSize:{}", idx,((ThreadPoolExecutor) executor).getQueue().size());
			countDownLatch.countDown();
		} catch (Throwable th) {
			LOGGER.error("RedisGuidService.create() throwable", th);
		} finally {
			executor.shutdown();
		}
		return set;
	}

	public synchronized void addLong(Long id){
		set.add(id);
	}
}
